// ignore_for_file: avoid_print

import 'dart:convert';
import 'dart:io';

import 'package:flujs/extension/console.dart';
import 'package:flujs/flujs.dart';
import 'package:flutter_test/flutter_test.dart';
// ignore: depend_on_referenced_packages
import 'package:path/path.dart' show join;
import 'package:flujs_jsc/jsc.dart' as jsc;
import 'package:flujs_qjs/qjs.dart' as qjs;

void main() {
  runEvalCode(JSFRuntime rt) async {
    var ctx = rt.newContext()..loadExtension();
    var res = ctx.eval('''eval('2+2')''');
    assert(res.isNumber());
    assert(res.toNumber() == 4);
    print('eval_code: ${res.toNumber()}');
  }

  runEvalWebpackCode(JSFRuntime rt) async {
    const source = '';
    final sourceStr = await File(
      join(Directory.current.path, 'test/integration/$source.js'),
    ).readAsString();
    var ctx = rt.newContext()..loadExtension();
    ctx.eval('''
var global = this;
window = global;
''');
    ctx.eval(sourceStr);
    ctx.eval('console.log(Object.keys(window))');

    var keys = ctx.globalObject.keys(ctx);
    Console.info('[keys]${keys.toArray()}');

    // assert(ctx.globalObject.hasProperty(source) == true);
    var sourceVar = ctx.globalObject.getProperty(source);
    if (sourceVar.hasProperty('default')) {
      sourceVar = sourceVar.getProperty('default');
    }
    Console.error(
      'sourceVar($source)=${sourceVar.toString()}, ${sourceVar.isUndefined()}',
    );

    var recommendSonglist = sourceVar.getProperty('recommendSonglist');
    // assert(recommendSonglist.isFunction());
    var lists = recommendSonglist.callAsFunction(thiz: sourceVar);
    assert(lists.isPromise());
    var listsRes = await ctx.runPromise(lists);
    print('res: $listsRes \n\n');
    print('[res] ${jsonDecode(jsonDecode(listsRes.toString()))[0]}');
  }

  runDartJsInterop(JSFRuntime rt) async {
    const code = '''
async function postsFn() {
  let res = await fetch(`http://localhost:3000/posts/0`);
  // res = await res.text();
  res = await res.json();
  console.log('postsFn', res);
  return JSON.stringify(res);
}
''';
    var ctx = rt.newContext()..loadExtension();
    ctx.eval(code);
    try {
      assert(ctx.globalObject.hasProperty('postsFn') == true);
      var posts = ctx.globalObject.getProperty('postsFn');
      assert(posts.isFunction());
      var promise = posts.callAsFunction();
      assert(promise.isPromise());
      var ret = await ctx.runPromise(promise);
      print('ret: $ret');
    } catch (e) {
      print('exception handler: $e');
    }
  }

  test('eval_code_jsc', () {
    var rt = jsc.getJSFRuntime();
    runEvalCode(rt);
  });
  test('eval_code_qjs', () {
    var rt = qjs.getJSFRuntime();
    runEvalCode(rt);
  });

  test('eval_webpack_jsc', () async {
    var rt = jsc.getJSFRuntime();
    await runEvalWebpackCode(rt);
  });
  test('eval_webpack_qjs', () async {
    var rt = qjs.getJSFRuntime();
    // (rt.rt as qjs.JSRuntime).setMaxStacKSize(10 * 1024);
    await runEvalWebpackCode(rt);
  });

  test('eval_interop_jsc', () async {
    var rt = jsc.getJSFRuntime();
    await runDartJsInterop(rt);
  });
  test('eval_interop_qjs', () async {
    var rt = qjs.getJSFRuntime();
    await runDartJsInterop(rt);
  });
}
